#include "systemc.h"

SC_MODULE(SimpleAPB)
{
	sc_in_clk PCLK;
	sc_in<bool> PRESETn;
	sc_in<int> PADDR; // 32bit wide
	sc_in<bool> PSELx;
	sc_in<bool> PENABLE;
	sc_in<bool> PWRITE;
	sc_in<int> PWDATA; // 32bit write data
	sc_out<bool> PREADY;
	sc_out<int> PRDATA;
	sc_out<bool> PSLVERR; // tie low
	int mem[1024];

	SC_CTOR(SimpleAPB)
	{
		SC_METHOD(trans);
		sensitive << PCLK.pos();
		sensitive << PRESETn.neg();
	}

	void trans()
	{
		if (PRESETn.read() == false)
		{
			PREADY.write(1);
			return;
		}

		if (PSELx.read() == true && PENABLE.read() == true)
		{
			int addr = (PADDR.read() >> 2) % 1024;

			PREADY.write(0);
			if (PWRITE.read() == false)
				PRDATA.write(mem[addr]);
			else
				mem[addr] = PWDATA.read();
			PREADY.write(1);
		}

		// if (PRESETn.read() == true && PWRITE.read() == false)
		// 	cout << __LINE__ << " : " << __func__ << ": " << sc_time_stamp() << endl;
	}
};

SC_MODULE(SimpleAPBMaster)
{
	/* 
		满足协议吗?
	 */
	sc_in_clk PCLK;
	sc_in<bool> PRESETn;
	sc_out<int> PADDR; // 32bit wide
	sc_out<bool> PSELx;
	sc_out<bool> PENABLE;
	sc_out<bool> PWRITE;
	sc_out<int> PWDATA; // 32bit write data
	sc_in<bool> PREADY;
	sc_in<int> PRDATA;
	sc_in<bool> PSLVERR; // tie low

	bool write_sel;
	bool start_trans;
	int addr;

	SC_CTOR(SimpleAPBMaster)
	{
		SC_CTHREAD(reset, PRESETn.neg());
		SC_CTHREAD(read, PCLK.pos());

		write_sel = true;
		start_trans = true;
		addr = 0;
	}

	void reset()
	{
		if (PRESETn.read() == false)
		{
			cout << __func__ << ": " << sc_time_stamp() << endl;
		}
	}

	void read()
	{
		// if (PRESETn.read() == false)
		// 	return;
		cout << __func__ << endl;
		while (true)
		{
			wait();
			if (start_trans && PREADY.read() == true)
			{
				PSELx.write(1);
				// cout << "===111===" << endl;
				wait();
				PADDR.write(addr);
				PENABLE.write(1);
				PWRITE.write(write_sel);
				if (write_sel)
				{
					PWDATA.write(addr);
				}
				// cout << "===" << endl;
				do
				{
					wait();
				} while (PREADY.read() == false);

				if (!write_sel)
				{
					cout << "read finish: 0x" << hex << addr << " read data: " << PRDATA.read() << endl;
					addr += 4;
				}
				PSELx.write(0);
				PENABLE.write(0);
				wait();
				write_sel = !write_sel;
			}
		}
	}
};

int sc_main(int argc, char *argv[])
{
	sc_signal<bool> PCLK;
	sc_signal<bool> PRESETn;
	sc_signal<int> PADDR; // 32bit wide
	sc_signal<bool> PSELx;
	sc_signal<bool> PENABLE;
	sc_signal<bool> PWRITE;
	sc_signal<int> PWDATA; // 32bit write data
	sc_signal<bool> PREADY;
	sc_signal<int> PRDATA;
	sc_signal<bool> PSLVERR; // tie low

	SimpleAPB uAPB("uapb0");
	uAPB.PCLK(PCLK);
	uAPB.PRESETn(PRESETn);
	uAPB.PADDR(PADDR);
	uAPB.PSELx(PSELx);
	uAPB.PENABLE(PENABLE);
	uAPB.PWRITE(PWRITE);
	uAPB.PWDATA(PWDATA);
	uAPB.PREADY(PREADY);
	uAPB.PRDATA(PRDATA);
	uAPB.PSLVERR(PSLVERR);

	SimpleAPBMaster uAPBm0("uapb_m0");
	uAPBm0.PCLK(PCLK);
	uAPBm0.PRESETn(PRESETn);
	uAPBm0.PADDR(PADDR);
	uAPBm0.PSELx(PSELx);
	uAPBm0.PENABLE(PENABLE);
	uAPBm0.PWRITE(PWRITE);
	uAPBm0.PWDATA(PWDATA);
	uAPBm0.PREADY(PREADY);
	uAPBm0.PRDATA(PRDATA);
	uAPBm0.PSLVERR(PSLVERR);

	// initlaize
	// sc_start(SC_ZERO_TIME);
	PRESETn.write(1);
	sc_start(1, SC_NS);
	PRESETn.write(0);
	sc_start(1, SC_NS);
	PRESETn.write(1);
	for (int i = 0; i < 1024; i++)
	// for (;;)
	{
		PCLK.write(0);
		sc_start(20, SC_NS);
		PCLK.write(1);
		sc_start(20, SC_NS);
		// cout << "==" << endl;
	}
	return 0;
}
